home *** CD-ROM | disk | FTP | other *** search
Java Source | 1996-05-23 | 9.8 KB | 456 lines |
- // ThreeDComponent.java
- // A component for displaying a wireframe 3d model. This uses a huge amount
- // of code ripped from the WireFrame demo that comes with the JDK.
- import java.awt.*;
- import java.io.*;
- import JFScomponent;
- import JFSclient;
- import FileReq;
- import DrawingPanel;
- import Drawing;
- import Matrix3D;
-
- public class ThreeDComponent extends JFScomponent
- {
- Button loadb;
- Choice buffer;
- ThreeDCanvas canv;
- FileReq loadreq;
-
- ThreeDComponent()
- {
- setLayout(new BorderLayout());
-
- // Create control panel
- Panel top = new Panel();
- top.setLayout(new FlowLayout(FlowLayout.LEFT));
- top.add(loadb = new Button("Load"));
- top.add(buffer = new Choice());
- buffer.addItem("Double buffer");
- buffer.addItem("Single buffer");
- add("North",top);
-
- // Create viewing panel
- canv = new ThreeDCanvas();
- BorderPanel bot = new BorderPanel(new Color(50,50,50),
- new Color(220,220,220));
- bot.setLayout(new BorderLayout());
- bot.add("Center",canv);
- add("Center",bot);
- }
-
- public boolean action(Event evt, Object obj)
- {
- if (evt.target == buffer) {
- // buffering mode chosen
- canv.setdouble(buffer.getSelectedIndex() == 0);
- }
- else if (evt.target == loadb && loadreq == null) {
- // load button clicked
- loadreq = new FileReq(client, this, "Load", "model/x-wavefront",
- false, null);
- }
- else if (evt.target == loadreq) {
- // Load requestor closed
- if (((String)evt.arg).equals("Load")) {
- // load a model
- try load(loadreq.getfile(), loadreq.getversion());
- catch(RequestException e)
- new ErrorWindow("Could not open "+
- loadreq.getfile()+" : "+
- e.getMessage());
- }
- loadreq = null;
- }
- return true;
- }
-
- // load
- // Load the given model for viewing
- void load(String file, int ver) throws RequestException
- {
- byte fd[] = client.get(file, ver);
- ByteArrayInputStream buf = new ByteArrayInputStream(fd);
- if (!canv.loadmodel(buf))
- throw new RequestException("Model format error");
- client.setcurrent(file);
- }
-
- Dimension wantedsize()
- {
- return new Dimension(400,400);
- }
- }
-
- class FileFormatException extends Exception {
- public FileFormatException(String s) {
- super(s);
- }
- }
-
- /** The representation of a 3D model */
- class Model3D {
- float vert[];
- int tvert[];
- int nvert, maxvert;
- int con[];
- int ncon, maxcon;
- boolean transformed;
- Matrix3D mat;
-
- float xmin, xmax, ymin, ymax, zmin, zmax;
-
- Model3D () {
- mat = new Matrix3D ();
- mat.xrot(20);
- mat.yrot(30);
- }
- /** Create a 3D model by parsing an input stream */
- Model3D (InputStream is) throws IOException, FileFormatException {
- this();
- StreamTokenizer st = new StreamTokenizer(is);
- st.eolIsSignificant(true);
- st.commentChar('#');
- scan:
- while (true) {
- switch (st.nextToken()) {
- default:
- break scan;
- case StreamTokenizer.TT_EOL:
- break;
- case StreamTokenizer.TT_WORD:
- if ("v".equals(st.sval)) {
- double x = 0, y = 0, z = 0;
- if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
- x = st.nval;
- if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
- y = st.nval;
- if (st.nextToken() == StreamTokenizer.TT_NUMBER)
- z = st.nval;
- }
- }
- addVert((float) x, (float) y, (float) z);
- while (st.ttype != StreamTokenizer.TT_EOL &&
- st.ttype != StreamTokenizer.TT_EOF)
- st.nextToken();
- } else if ("f".equals(st.sval) || "fo".equals(st.sval) || "l".equals(st.sval)) {
- int start = -1;
- int prev = -1;
- int n = -1;
- while (true)
- if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
- n = (int) st.nval;
- if (prev >= 0)
- add(prev - 1, n - 1);
- if (start < 0)
- start = n;
- prev = n;
- } else if (st.ttype == '/')
- st.nextToken();
- else
- break;
- if (start >= 0)
- add(start - 1, prev - 1);
- if (st.ttype != StreamTokenizer.TT_EOL)
- break scan;
- } else {
- while (st.nextToken() != StreamTokenizer.TT_EOL
- && st.ttype != StreamTokenizer.TT_EOF);
- }
- }
- }
- is.close();
- if (st.ttype != StreamTokenizer.TT_EOF)
- throw new FileFormatException(st.toString());
- }
-
- /** Add a vertex to this model */
- int addVert(float x, float y, float z) {
- int i = nvert;
- if (i >= maxvert)
- if (vert == null) {
- maxvert = 100;
- vert = new float[maxvert * 3];
- } else {
- maxvert *= 2;
- float nv[] = new float[maxvert * 3];
- System.arraycopy(vert, 0, nv, 0, vert.length);
- vert = nv;
- }
- i *= 3;
- vert[i] = x;
- vert[i + 1] = y;
- vert[i + 2] = z;
- return nvert++;
- }
- /** Add a line from vertex p1 to vertex p2 */
- void add(int p1, int p2) {
- int i = ncon;
- if (p1 >= nvert || p2 >= nvert)
- return;
- if (i >= maxcon)
- if (con == null) {
- maxcon = 100;
- con = new int[maxcon];
- } else {
- maxcon *= 2;
- int nv[] = new int[maxcon];
- System.arraycopy(con, 0, nv, 0, con.length);
- con = nv;
- }
- if (p1 > p2) {
- int t = p1;
- p1 = p2;
- p2 = t;
- }
- con[i] = (p1 << 16) | p2;
- ncon = i + 1;
- }
- /** Transform all the points in this model */
- void transform() {
- if (transformed || nvert <= 0)
- return;
- if (tvert == null || tvert.length < nvert * 3)
- tvert = new int[nvert*3];
- mat.transform(vert, tvert, nvert);
- transformed = true;
- }
-
- private void sort(int lo0, int hi0) {
- int a[] = con;
- int lo = lo0;
- int hi = hi0;
- if (lo >= hi)
- return;
- int mid = a[(lo + hi) / 2];
- while (lo < hi) {
- while (lo < hi && a[lo] < mid) {
- lo++;
- }
- while (lo < hi && a[hi] >= mid) {
- hi--;
- }
- if (lo < hi) {
- int T = a[lo];
- a[lo] = a[hi];
- a[hi] = T;
- }
- }
- if (hi < lo) {
- int T = hi;
- hi = lo;
- lo = T;
- }
- sort(lo0, lo);
- sort(lo == lo0 ? lo + 1 : lo, hi0);
- }
-
- /** eliminate duplicate lines */
- void compress() {
- int limit = ncon;
- int c[] = con;
- sort(0, ncon - 1);
- int d = 0;
- int pp1 = -1;
- for (int i = 0; i < limit; i++) {
- int p1 = c[i];
- if (pp1 != p1) {
- c[d] = p1;
- d++;
- }
- pp1 = p1;
- }
- ncon = d;
- }
-
- static Color gr[];
-
- /** Paint this model to a graphics context. It uses the matrix associated
- with this model to map from model space to screen space.
- The next version of the browser should have double buffering,
- which will make this *much* nicer */
- void paint(Graphics g) {
- if (vert == null || nvert <= 0)
- return;
- transform();
- if (gr == null) {
- gr = new Color[16];
- for (int i = 0; i < 16; i++) {
- int grey = (int) (170*(1-Math.pow(i/15.0, 2.3)));
- gr[i] = new Color(grey, grey, grey);
- }
- }
- int lg = 0;
- int lim = ncon;
- int c[] = con;
- int v[] = tvert;
- if (lim <= 0 || nvert <= 0)
- return;
- for (int i = 0; i < lim; i++) {
- int T = c[i];
- int p1 = ((T >> 16) & 0xFFFF) * 3;
- int p2 = (T & 0xFFFF) * 3;
- int grey = v[p1 + 2] + v[p2 + 2];
- if (grey < 0)
- grey = 0;
- if (grey > 15)
- grey = 15;
- if (grey != lg) {
- lg = grey;
- g.setColor(gr[grey]);
- }
- g.drawLine(v[p1], v[p1 + 1],
- v[p2], v[p2 + 1]);
- }
- }
-
- /** Find the bounding box of this model */
- void findBB() {
- if (nvert <= 0)
- return;
- float v[] = vert;
- float xmin = v[0], xmax = xmin;
- float ymin = v[1], ymax = ymin;
- float zmin = v[2], zmax = zmin;
- for (int i = nvert * 3; (i -= 3) > 0;) {
- float x = v[i];
- if (x < xmin)
- xmin = x;
- if (x > xmax)
- xmax = x;
- float y = v[i + 1];
- if (y < ymin)
- ymin = y;
- if (y > ymax)
- ymax = y;
- float z = v[i + 2];
- if (z < zmin)
- zmin = z;
- if (z > zmax)
- zmax = z;
- }
- this.xmax = xmax;
- this.xmin = xmin;
- this.ymax = ymax;
- this.ymin = ymin;
- this.zmax = zmax;
- this.zmin = zmin;
- }
- }
-
- // ThreeDCanvas
- // The component where the action takes place.
- class ThreeDCanvas extends Canvas {
- Model3D md; // the 3d object to draw, or null
- float xfac;
- int prevx, prevy;
- float xtheta, ytheta;
- float scalefudge = 1;
- Matrix3D amat = new Matrix3D(),
- tmat = new Matrix3D();
- String mdname = null;
- Image dbuf;
- boolean wireframe = true,
- doublebuffer = true;
-
- // loadmodel
- // Set the current model to one loaded from the given stream
- boolean loadmodel(InputStream is)
- {
- try {
- Model3D m = new Model3D (is);
- md = m;
- m.findBB();
- m.compress();
- dbuf = null;
- }
- catch(Exception e)
- return false;
- paint(getGraphics());
- return true;
- }
-
- // setwire
- // Enable or disable wireframe rendering
- void setwire(boolean w)
- {
- wireframe = w;
- paint(getGraphics());
- }
-
- // setdouble
- // Enable or disable double-buffered rendering
- void setdouble(boolean d)
- {
- doublebuffer = d;
- paint(getGraphics());
- }
-
- public boolean mouseDown(Event e, int x, int y)
- {
- prevx = x;
- prevy = y;
- return true;
- }
-
- public boolean mouseDrag(Event e, int x, int y)
- {
- tmat.unit();
- float xtheta = (prevy - y) * 360.0f / size().width;
- float ytheta = (x - prevx) * 360.0f / size().height;
- tmat.xrot(xtheta);
- tmat.yrot(ytheta);
- amat.mult(tmat);
- repaint();
- prevx = x;
- prevy = y;
- return true;
- }
-
- public void update(Graphics g)
- {
- paint(g);
- }
-
- // paint
- // Render the model into a backing image, and blit to the front
- public void paint(Graphics fg)
- {
- if (fg == null) return;
- if (dbuf == null || dbuf.getWidth(this) != size().width ||
- dbuf.getHeight(this) != size().height) {
- // we have been resized
- dbuf = createImage(size().width, size().height);
- float xw = md.xmax - md.xmin;
- float yw = md.ymax - md.ymin;
- float zw = md.zmax - md.zmin;
- if (yw > xw)
- xw = yw;
- if (zw > xw)
- xw = zw;
- float f1 = size().width / xw;
- float f2 = size().height / xw;
- xfac = 0.7f * (f1 < f2 ? f1 : f2) * scalefudge;
- }
- Graphics g;
- if (doublebuffer) g = dbuf.getGraphics();
- else g = fg;
-
- g.setColor(Color.lightGray);
- g.fillRect(0, 0, size().width, size().height);
- if (md != null) {
- md.mat.unit();
- md.mat.translate(-(md.xmin + md.xmax) / 2,
- -(md.ymin + md.ymax) / 2,
- -(md.zmin + md.zmax) / 2);
- md.mat.mult(amat);
- md.mat.scale(xfac, -xfac, 16 * xfac / size().width);
- md.mat.translate(size().width / 2, size().height / 2, 8);
- md.transformed = false;
- md.paint(g);
- }
- if (doublebuffer) fg.drawImage(dbuf, 0, 0, this);
- }
- }
-
-